package com.zhijl.common.encryptor.asymmetric;

import com.zhijl.common.encryptor.symmetric.SM4;
import com.zhijl.common.encryptor.symmetric.SM4Impl;
import org.apache.commons.lang3.StringUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * 〈〉
 *
 * @author Administrator
 * @date 2018/8/31
 * @since 1.0.0
 */
public class SM2SelfedCert {

    private String skCert;
    private String pemCert;

    /**
     * 生成自签名证书公钥证书对应json key的名称
     */
    private final static String priKeyJsonKey = "sk";

    /**
     * 生成自签名证书私钥证书对应json key的名称
     */
    private final static String pubKeyJsonKey = "pem";

    public SM2SelfedCert(String skCert) {
        this.skCert = skCert;
    }

    public SM2SelfedCert(String skCert, String pemCert) {
        this.skCert = skCert;
        this.pemCert = pemCert;
    }

    public String getSkCert() {
        return skCert;
    }

    public void setSkCert(String skCert) {
        this.skCert = skCert;
    }


    public String getPemCert() {
        return pemCert;
    }

    public String toJsonString() {
        return StringUtils.join("{\"" + priKeyJsonKey + "\":\"", skCert, "\",",
                "\"" + pubKeyJsonKey + "\":\"", pemCert, "\"}");
    }

    private final SM4 sm4 = new SM4Impl();

    /**
     * @throws RuntimeException 加密失败/输入输出流关闭失败
     */
    public void encryptSKBySM4(String password) {

        password = checkPassWord(password);

        ByteArrayInputStream is = new ByteArrayInputStream(this.getSkCert().getBytes(StandardCharsets.UTF_8));
        ByteArrayOutputStream os = new ByteArrayOutputStream(2000);

        try {
            sm4.encryptStream(is, os, password.getBytes(StandardCharsets.UTF_8));
            this.skCert = Base64.getEncoder().encodeToString(os.toByteArray());
        } catch (IOException e) {
            throw new RuntimeException("sm4 加密私钥失败");
        } finally {
            try {
                is.close();
                os.close();
            } catch (IOException e) {
                throw new RuntimeException("sm4 加密私钥输入输出流关闭失败");
            }
        }
    }


    /**
     * @throws RuntimeException 加密失败/输入输出流关闭失败
     */
    public void decryptSKBySM4(String password) {

        password = checkPassWord(password);

        ByteArrayInputStream is = new ByteArrayInputStream(Base64.getDecoder().decode(this.skCert));
        ByteArrayOutputStream os = new ByteArrayOutputStream(2000);

        try {
            sm4.decryptStream(is, os, password.getBytes(StandardCharsets.UTF_8));
            this.skCert = new String(os.toByteArray(), StandardCharsets.UTF_8);
        } catch (IOException e) {
            throw new RuntimeException("sm4 加密私钥失败");
        } finally {
            try {
                is.close();
                os.close();
            } catch (IOException e) {
                throw new RuntimeException("sm4 加密私钥输入输出流关闭失败");
            }
        }
    }

    private String checkPassWord(String password) {
        if (password.length() < 8) {
            throw new RuntimeException("password length must more than 8");
        } else if (password.length() < 16) {
            password = StringUtils.join(password, password).substring(0, 16);
        }else if (password.length() > 20){
            throw new RuntimeException("password length too long for 20");
        }
        return password;
    }

}
